/**
 * @fileOverview
 * to manage all components status
 * @author huangtonger@aliyun.com
 */

const Base = require('../base');
const Util = require('../util');
const Command = require('../command');

class Editor extends Base {
  getDefaultCfg() {
    return {
      _components: [],
      _command: {
        zoomDelta: 0.1, // 缩放步长
        queue: [], // 回退堆栈
        current: 0, // 不是索引，是第 N 个数组元素
        clipboard: [] // 剪贴板
      }
    };
  }
  _getComponentsBy(callback) {
    const components = this.get('_components');
    return components.filter(callback);
  }
  // 绑定命令
  _bindCommands(commandDoms) {
    Util.each(commandDoms, commandDom => {
      const dataset = commandDom.dataset;
      const commandName = dataset.command;
      if (!Command[commandName]) {
        console.warn('请设置有效的命令！');
      } else {
        Util.addEventListener(commandDom, 'click', () => {
          const page = this.getCurrentPage();
          page.focusGraphWrapper();
          this.executeCommand(commandName, dataset);
        });
      }
    });
  }
  getCommands() {
    return this.get('_command').queue;
  }
  getCurrentCommand() {
    const commandCfg = this.get('_command');
    const { queue, current } = commandCfg;
    return queue[current - 1];
  }
  executeCommand(param, cfg) {
    if (Util.isString(param)) {
      Command.execute(param, this, cfg);
    } else {
      Command.execute('common', this, {
        method: param
      }, cfg);
    }
  }
  commandEnable(name) {
    return Command.enable(name, this);
  }
  setCommandDOMenable() {
    const toolbars = this.getComponentsByType('toolbar');
    const contextmenus = this.getComponentsByType('contextmenu');
    const commandDoms = [];
    toolbars.forEach(toolbar => {
      Util.each(toolbar.getCommandDoms(), commandDom => {
        commandDoms.push(commandDom);
      });
    });
    contextmenus.forEach(contextmenu => {
      Util.each(contextmenu.getCommandDoms(), commandDom => {
        commandDoms.push(commandDom);
      });
    });
    Util.each(commandDoms, commandDom => {
      const dataset = commandDom.dataset;
      const commandName = dataset.command;

      if (!Command.enable(commandName, this)) {
        commandDom.classList.add('disable');
      } else {
        commandDom.classList.remove('disable');
      }
    });
  }
  // 当画板状态变更
  _onPageStatusChange() {
    this.setCommandDOMenable();
  }
  _beforeAddMinimap(minimap) {
    const pages = this.getComponentsByType('page');
    minimap.getGraph = () => {
      return this.getCurrentPage().getGraph();
    };
    if (pages.length === 0) {
      // 如果没有当前页面返回
      return;
    }
    pages.forEach(page => {
      minimap.bindPage(page);
    });
  }
  _afterAddContextmenu() {
    this.getCurrentPage() && this.setCommandDOMenable();
  }
  _afterAddPage(page) {
    const minimaps = this.getComponentsByType('minimap');
    this.setCommandDOMenable();
    minimaps.forEach(minimap => {
      minimap.bindPage(page);
    });
    page.on('statuschange', ev => {
      this._onPageStatusChange(ev);
    });
    page.on('mousedown', () => {
      const contextmenus = this.getComponentsByType('contextmenu');
      contextmenus.forEach(contextmenu => {
        contextmenu.hide();
      });
    });
    page.on('contextmenu', ev => {
      const contextmenus = this.getComponentsByType('contextmenu');
      const graph = page.getGraph();
      const canvas = graph.getCanvas();
      const el = canvas.get('el');
      const boundingRect = Util.getBoundingClientRect(el);
      const contextmenuPoint = {
        x: ev.x,
        y: ev.y
      };
      const { item } = ev;
      if (item && !item.isSelected) {
        page.clearSelected();
        page.setSelected(ev.item, true);
      }
      this.set('contextmenuPoint', contextmenuPoint);
      ev.domEvent.preventDefault();
      contextmenus.forEach(contextmenu => {
        contextmenu.show();
        contextmenu.contextmenuPoint = contextmenuPoint;
        contextmenu.move(boundingRect.left + ev.domX, boundingRect.top + ev.domY);
      });
    });
    page.on('statuschange', ev => {
      const contextmenus = this.getComponentsByType('contextmenu');
      const detailpanels = this.getComponentsByType('detailpanel');
      contextmenus.forEach(contextmenu => {
        contextmenu.switch(ev.status);
      });
      detailpanels.forEach(detailpanel => {
        detailpanel.switch(ev.status);
      });
    });
    this._bindShortcut(page);
  }
  _beforeAddToolbar(toolbar) {
    const commandDoms = toolbar.getCommandDoms();
    this._bindCommands(commandDoms);
  }
  _beforeAddContextmenu(contextmenu) {
    const commandDoms = contextmenu.getCommandDoms();
    contextmenu.bindEvent();
    this._bindCommands(commandDoms);
  }
  _beforeAddItempanel(itempanel) {
    itempanel.bindEvent();
  }
  getComponentsByType(type) {
    return this._getComponentsBy(component => {
      return component.type === type;
    });
  }
  /**
   * 获取激活的页面
   * @return  {Page} page
   */
  getCurrentPage() {
    const pages = this.getComponentsByType('page');
    let rst;
    pages.every(page => {
      if (page.isActived) {
        rst = page;
        return false;
      }
      return true;
    });
    if (!rst) {
      rst = pages[0];
    }
    return rst;
  }
  /**
   * 获取所有的组建
   * @return  {array} 组建集
   */
  getComponents() {
    return this.get('_components');
  }
  // 判断该快捷键下命令是否执行
  _shortcutEnable(command, domEvent) {
    const shortcutCodes = command.shortcutCodes;
    const key = Util.getKeyboradKey(domEvent);
    let bool = false;
    for (let i = 0; i < shortcutCodes.length; i++) {
      const shortcutCode = shortcutCodes[i];
      if (Util.isArray(shortcutCode)) {
        const l = shortcutCode.length;
        let subBool = true;
        for (let j = 0; j < l - 1; j++) {
          if (!domEvent[shortcutCode[j]]) {
            subBool = false;
            break;
          }
        }
        if ((shortcutCode[l - 1] === key || shortcutCode[l - 1] === Util.lowerFirst(key)) && subBool) {
          bool = true;
        }
      } else {
        if (shortcutCode === key) {
          bool = true;
        }
      }
      if (bool) {
        break;
      }
    }
    return bool;
  }
  /**
   * 绑定快捷键
   * @param  {object} page page or array
   */
  _bindShortcut(page) {
    const shortcut = page.get('shortcut');
    const graph = page.getGraph();
    graph.on('keydown', ev => {
      const contextmenus = this.getComponentsByType('contextmenu');
      const { domEvent } = ev;
      contextmenus.forEach(contextmenu => {
        contextmenu.hide();
      });
      domEvent.preventDefault();
      const commands = Command.list.filter(command => {
        return command.shortcutCodes && shortcut[command.name];
      });

      for (let index = 0; index < commands.length; index++) {
        const command = commands[index];
        if (this._shortcutEnable(command, domEvent)) {
          this.executeCommand(command.name);
          return false;
        }
      }
    });
  }
  add(component) {
    const components = this.get('_components');
    const type = Util.upperFirst(component.type);
    component.editor = this;
    this['_beforeAdd' + type] && this['_beforeAdd' + type](component);
    components.push(component);
    this['_afterAdd' + type] && this['_afterAdd' + type](component);
  }
  destroy() {
    const components = this.get('_components');
    components.forEach(component => {
      component.destroy();
    });
  }
}

module.exports = Editor;
